﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Lang {
    /*
     * 这里定义了所有的中缀运算的方法
     * 方法返回值和参数列表都是一致的
     * 基本逻辑都是从参数了列表中分别获取左右两边的参数
     * 由于是动态类型语言
     * 所有需要对参数进行类型判断后，选择相应的运算方式
     */

    class Op {

        public static bool IsSetOrDimOp(Expr expr) {
            return expr.Tp == TP.Op && (
                    expr.Str() == "="
                    || expr.Str() == "："
                    || expr.Str() == ":"
                    || expr.Str() == "为"
                    || expr.Str() == "设为"
                );
        } 


/*        public static Expr DimVar(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0];
            Expr arg1 = args[1].Eval(ctx);


            if (arg0.tp == TP.Var && arg1.tp != TP.Func) {
                ctx.PutNow(arg0.Str(), arg1.Dup()); ;
                return arg1;

            } else if (arg0.tp == TP.Act && arg1.tp == TP.Func) {
                ctx.PutNow(arg0.Str(), arg1.Dup()); ;
                return arg1;

            } else if ((arg0.tp == TP.Var_path && arg1.tp != TP.Func)
                || (arg0.tp == TP.Act_path && arg1.tp == TP.Func)) {
                Expr k = arg0.list![arg0.list!.Count - 1];
                arg0.list.RemoveAt(arg0.list!.Count - 1);
                Expr obj = Expr.ReducePath(arg0.list!, ctx);
                if (obj.tp != TP.Obj || k.tp != TP.Str) {
                    return Expr.Err("定义变量语句参数类型错误");
                }
                obj.Obj().PutNow(k.Str(), arg1.Dup());
                return arg1;

            }

            return Expr.Err("定义变量语句参数类型错误");
        }*/


        public static Expr DimVar(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0];
            Expr arg1 = args[1];
            if(arg1.Tp < TP.Var) {
                arg1 = arg1.Clone();
            } else {
                arg1 = arg1.Eval(ctx);
            };

            if (arg0.Tp == TP.Var && (arg1.Tp != TP.Func && arg1.Tp != TP.Native)) {
                ctx.PutNow(arg0.Str(), arg1.Dup()); ;
                return arg1;

            } else if (arg0.Tp == TP.Act && (arg1.Tp == TP.Func || arg1.Tp == TP.Native|| arg1.Tp == TP.None)) {
                ctx.PutNow(arg0.Str(), arg1.Dup()); ;
                return arg1;

            } else if (arg0.Tp == TP.Path) {
                Expr k = arg0.List![arg0.List!.Count - 1];
                if (k.Tp == TP.Block) {
                    k = Expr.EvalExprs(k.List!, ctx);
                }
                List<Expr> list = new List<Expr>(arg0.List!);
                list.RemoveAt(arg0.List!.Count - 1);
                Expr coll = Expr.ReducePath(list, ctx, arg0);
                if(coll.Tp == TP.Obj) {
                    if (k.Tp != TP.Str) {
                        return Expr.Err("对象定义属性名的格式错误");
                    }
                    if (k.Str().StartsWith("#") && (arg1.Tp == TP.Func || arg1.Tp == TP.Native)) {
                        return Expr.Err("定义变量语句参数类型错误");
                    }
                    if (k.Str().StartsWith("@") && (arg1.Tp != TP.Func && arg1.Tp != TP.Native)) {
                        return Expr.Err("定义变量语句参数类型错误");
                    }

                    Expr prop = coll.Obj().GetNow(k.Str());
                    if (prop.Tp == TP.Prop) {

                        prop.Prop().Qset(arg1.Dup());


                    } else {
                        coll.Obj().PutNow(k.Str(), arg1.Dup());
                    }
                    return coll;

                }else if(coll.Tp == TP.Arr) {
                    if(k.Tp == TP.Str) {
                        k = ctx.Get(k.Str());
                    }
                    if(k.Tp != TP.Int) {
                        return Expr.Err("数组定义值路径错误");
                    }
                    if (k.Int() > coll.List!.Count) {
                        return Expr.Err("数组定义值下标越界");
                    }
                    if (k.Int() == coll.List!.Count) {
                        coll.List!.Add(arg1.Dup());
                        return coll;
                    }
                    if (k.Int() < coll.List!.Count) {
                        coll.List![k.Int()] = arg1.Dup();
                        return coll;
                    }
                }

            }

            return Expr.Err("定义变量语句参数类型错误");
        }

/*        public static Expr SetVar(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0];
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.tp == TP.Var && arg1.tp != TP.Func) {
                ctx.Put(arg0.Str(), arg1.Dup()) ;
                return arg1;

            } else if (arg0.tp == TP.Act && arg1.tp == TP.Func) {
                ctx.Put(arg0.Str(), arg1.Dup()); ;
                return arg1;

            }else if(arg0.tp == TP.Var_path || arg0.tp == TP.Act_path) {
                Expr k = arg0.list![arg0.list!.Count - 1];
                arg0.list.RemoveAt(arg0.list!.Count - 1);
                Expr curr = Expr.ReducePath(arg0.list!, ctx);
                if(curr.tp == TP.Obj && k.tp == TP.Str) {
                    if((arg0.tp == TP.Var_path && arg1.tp != TP.Func)
                        || (arg0.tp == TP.Act_path && arg1.tp == TP.Func)) {
                        curr.Obj().PutNow(k.Str(), arg1.Dup());
                        return arg1;
                    }                   
                }else if(curr.tp == TP.Arr && k.tp == TP.Int) {
                    if(k.Int() < curr.list!.Count) {
                        curr.list![k.Int()] = arg1.Dup();
                    }else if(k.Int() == curr.list!.Count) {
                        curr.list!.Add(arg1.Dup());
                    } else {
                        return Expr.Err("路径设值语句越界");
                    }
                    return arg1;
                }

            }

            return Expr.Err("变量设值语句参数类型错误");
        }*/


        public static Expr SetVar(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0];
            Expr arg1 = args[1];
            if (arg1.Tp < TP.Var) {
                arg1 = arg1.Clone();
            } else {
                arg1 = arg1.Eval(ctx);
            };

            if (arg0.Tp == TP.Var && (arg1.Tp != TP.Func && arg1.Tp != TP.Native)) {
                ctx.Put(arg0.Str(), arg1.Dup());
                return arg1;

            } else if (arg0.Tp == TP.Act && (arg1.Tp == TP.Func || arg1.Tp == TP.Native)) {
                ctx.Put(arg0.Str(), arg1.Dup()); ;
                return arg1;

            } else if (arg0.Tp == TP.Path) {
                Expr k = arg0.List![arg0.List!.Count - 1];
                if (k.Tp == TP.Block) {
                    k = Expr.EvalExprs(k.List!, ctx);
                }
                List<Expr> list = new List<Expr>(arg0.List!);
                list.RemoveAt(arg0.List!.Count - 1);
                Expr coll = Expr.ReducePath(list, ctx, arg0);
                if (coll.Tp == TP.Obj) {
                    if (k.Tp != TP.Str) {
                        return Expr.Err("对象设值属性名的格式错误");
                    }
                    if (k.Str().StartsWith("#") && (arg1.Tp == TP.Func || arg1.Tp == TP.Native)) {
                        return Expr.Err("设置变量语句参数类型错误");
                    }
                    if (k.Str().StartsWith("@") && (arg1.Tp != TP.Func && arg1.Tp != TP.Native)) {
                        return Expr.Err("设置变量语句参数类型错误");
                    }

                    Expr prop = coll.Obj().GetNow(k.Str());
                    if (prop.Tp == TP.Prop) {

                        prop.Prop().Qset(arg1.Dup());

                    } else {
                        coll.Obj().PutNow(k.Str(), arg1.Dup());
                    }
                    return coll;
                }else if(coll.Tp == TP.Arr) {
                    if (k.Tp == TP.Str) {
                        k = ctx.Get(k.Str());
                    }
                    if (k.Tp != TP.Int) {
                        return Expr.Err("数组设值路径错误");
                    }
                    if (k.Int() > coll.List!.Count) {
                        return Expr.Err("设置变量语句下标越界");
                    }
                    if (k.Int() == coll.List!.Count) {
                        coll.List!.Add(arg1.Dup());
                        return coll;
                    }
                    if (k.Int() < coll.List!.Count) {
                        coll.List![k.Int()] = arg1.Dup();
                        return coll;
                    }

                }

            }
            
            return Expr.Err("变量设值语句参数类型错误");
        }





        public static Expr Add(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Int, arg0.Int() + arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Int() + arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, arg0.Float() + arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Float() + arg1.Float());
                }
            }

            if (arg0.Tp == TP.Str && arg1.Tp == TP.Str) {
                return new Expr(TP.Str, arg0.Str() + arg1.Str());
            }
            if (arg0.Tp == TP.Str) {
                return new Expr(TP.Str, arg0.Str() + arg1.ToStr());
            }
            if (arg1.Tp == TP.Str) {
                return new Expr(TP.Str, arg0.ToStr() + arg1.Str());
            }

            return Expr.Err("加法运算参数类型错误");
        }

        public static Expr Sub(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Int, arg0.Int() - arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Int() - arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, arg0.Float() - arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Float() - arg1.Float());
                }
            }
            if (arg0.Tp == TP.Str && arg1.Tp == TP.Str) {
                int i = 0;
                string source = arg0.Str();
                string target = arg1.Str();
                while (i < source.Length - target.Length - 1) {
                    if (source[i..(i+target.Length)] == target) {
                        return new Expr(TP.Str, source[0..i] + source[(i+target.Length)..]);
                    }
                    i++;
                }
                return new Expr(TP.Str, source);
            }

            return Expr.Err("减法运算参数类型错误");
        }

        public static Expr Mul(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Int, arg0.Int() * arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Int() * arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, arg0.Float() * arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Float() * arg1.Float());
                }
            }
            if (arg0.Tp == TP.Str && arg1.Tp == TP.Int) {
                string str = arg0.Str();
                string s = str;
                for (int i = 0; i<arg1.Int(); i++) {
                    str += s;
                }
                return new Expr(TP.Str, str);
            }

            return Expr.Err("乘运算参数类型错误");
        }

        public static Expr Div(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, (decimal)arg0.Int() / (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Int() / arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, arg0.Float() / arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, arg0.Float() / arg1.Float());
                }
            }
            if (arg0.Tp == TP.Str && arg1.Tp == TP.Int) {
                int len = arg0.Str().Length / arg1.Int();
                return new Expr(TP.Str, arg0.Str()[0..len]);
            }

            return Expr.Err("除法运算参数类型错误");
        }


        public static Expr Mod(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int && arg1.Tp == TP.Int) {
                return new Expr(TP.Int, arg0.Int() % arg1.Int());
            }

            return Expr.Err("取模运算参数类型错误");
        }

        public static Expr Power(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Int, (int)Math.Pow(arg0.Int(), arg1.Int()));

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, (decimal)Math.Pow(arg0.Int(), (double)arg1.Float()));
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Float, (decimal)Math.Pow((double)arg0.Float(), arg1.Int()));

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Float, (decimal)Math.Pow((double)arg0.Float(), (double)arg1.Float()));
                }
            }
            if (arg0.Tp == TP.Str && arg1.Tp == TP.Int) {
                int len = arg0.Str().Length / arg1.Int();
                return new Expr(TP.Str, arg0.Str()[0..len]);
            }

            return Expr.Err("乘方运算参数类型错误");
        }


        public static Expr Eq(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);
            bool b = arg0.Eq(arg1);
            return new Expr(TP.Bool, b);

            /*if (arg0.tp == TP.Int) {
                if (arg1.tp == TP.Int) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() == (decimal)arg1.Int());

                } else if (arg1.tp == TP.Float) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() == arg1.Float());
                }

            } else if (arg0.tp == TP.Float) {
                if (arg1.tp == TP.Int) {
                    return new Expr(TP.Bool, arg0.Float() == (decimal)arg1.Int());

                } else if (arg1.tp == TP.Float) {
                    return new Expr(TP.Bool, arg0.Float() == arg1.Float());
                }
            }

            return Expr.Err( "等于运算参数类型错误");*/
        }

        public static Expr Ne(List<Expr> args, Ctx ctx) {
            Expr ret = Eq(args, ctx);
            ret.Val = !(bool)ret.Val;
            return ret;
        }

        public static Expr Le(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() <= (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() <= arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, arg0.Float() <= (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, arg0.Float() <= arg1.Float());
                }
            }

            return Expr.Err("小于等于运算参数类型错误");
        }


        public static Expr Ge(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() >= (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() >= arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, arg0.Float() >= (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, arg0.Float() >= arg1.Float());
                }
            }

            return Expr.Err("大于等于运算参数类型错误");
        }


        public static Expr Lt(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() < (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() < arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, arg0.Float() < (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, arg0.Float() < arg1.Float());
                }
            }

            return Expr.Err("小于运算参数类型错误");
        }


        public static Expr Gt(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() > (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, (decimal)arg0.Int() > arg1.Float());
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    return new Expr(TP.Bool, arg0.Float() > (decimal)arg1.Int());

                } else if (arg1.Tp == TP.Float) {
                    return new Expr(TP.Bool, arg0.Float() > arg1.Float());
                }
            }

            return Expr.Err("大于运算参数类型错误");
        }

        public static Expr And(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            if (!arg0.ToBool()) {
                return new Expr(TP.Bool, false);
            }

            Expr arg1 = args[1].Eval(ctx);

            return new Expr(TP.Bool, arg1.ToBool());
        }

        public static Expr Or(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            if (arg0.ToBool()) {
                return new Expr(TP.Bool, true);
            }

            Expr arg1 = args[1].Eval(ctx);

            return new Expr(TP.Bool, arg1.ToBool());
        }


        public static Expr AddSet(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Int() + arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val =  arg0.Int() + arg1.Float();
                    return arg0;
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val =  arg0.Float() + arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Float() + arg1.Float();
                    return arg0;
                }
            }

            return Expr.Err("自加运算参数类型错误");
        }

        public static Expr SubSet(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Int() - arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Int() - arg1.Float();
                    return arg0;
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Float() - arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Float() - arg1.Float();
                    return arg0;
                }
            }

            return Expr.Err("自减运算参数类型错误");
        }

        public static Expr MulSet(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Int() * arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Int() * arg1.Float();
                    return arg0;
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Float() * arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Float() * arg1.Float();
                    return arg0;
                }
            }

            return Expr.Err("自乘运算参数类型错误");
        }

        public static Expr DivSet(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = (decimal)arg0.Int() / (decimal)arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Int() / arg1.Float();
                    return arg0;
                }

            } else if (arg0.Tp == TP.Float) {
                if (arg1.Tp == TP.Int) {
                    arg0.Val = arg0.Float() / arg1.Int();
                    return arg0;

                } else if (arg1.Tp == TP.Float) {
                    arg0.Val = arg0.Float() / arg1.Float();
                    return arg0;
                }
            }

            return Expr.Err("自除运算参数类型错误");
        }

        public static Expr ModSet(List<Expr> args, Ctx ctx) {
            Expr arg0 = args[0].Eval(ctx);
            Expr arg1 = args[1].Eval(ctx);

            if (arg0.Tp == TP.Int && arg1.Tp == TP.Int) {
                arg0.Val = arg0.Int() % arg1.Int();
                return arg0;
            }

            return Expr.Err("自模运算参数类型错误");
        }

    }
}
